package net.melon.agency.inst.ssh.service.impl;

import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.inject.Named;
import javax.inject.Singleton;

import net.esj.auth.AuthException;
import net.esj.auth.pojo.CoreAuthFunc;
import net.esj.basic.dao.hibernate.HibernateDao;
import net.esj.basic.dao.querybuilder.QueryBuilder;
import net.esj.basic.dao.querybuilder.SymbolExpression;
import net.esj.basic.service.impl.DefaultServiceImpl;
import net.esj.basic.service.provider.UserRuleProvider;
import net.esj.basic.utils.Assert;
import net.esj.basic.utils.Pagination;
import net.esj.basic.utils.StringUtils;
import net.esj.basic.utils.Validators;
import net.melon.agency.inst.ssh.service.AuthService;
import net.melon.agency.pojo.Agency;
import net.melon.agency.pojo.AgencyGroup;
import net.melon.agency.pojo.AgencyGroupFunc;
import net.melon.agency.pojo.AgencyUser;
import net.melon.agency.pojo.AgencyUserGroup;

@Named("authService")
@Singleton
public class AuthServiceImpl extends DefaultServiceImpl implements AuthService {

	@Override
	public String deleteGroup(AgencyGroup group) throws AuthException {
		QueryBuilder<AgencyUserGroup> qb = createQueryBuilder(AgencyUserGroup.class);
		qb.eq("groupId", group.getId());
		int c = queryCountByQueryBuilder(qb);
		if(c>0){
			throw new AuthException("auth.group.used");
		}
		deleteGroupFuncByGroup(group.getId());
		delete(group);
		return group.getName();
	}

	@Override
	public AgencyUser getUserWithAuth(String id) {
		AgencyUser user = get(id, AgencyUser.class);
		if(user.isSuper()){
			QueryBuilder<CoreAuthFunc> qb = createQueryBuilder(CoreAuthFunc.class);
			qb.eq("model.id", UserRuleProvider.getUserRule(AgencyUser.class).getAuthModel()).eq("disabled", false).OrderByAsc("sort");
			List<CoreAuthFunc> list = queryListByQueryBuilder(qb);
			user.setFuncs(new HashSet<CoreAuthFunc>(list));
		}
		
		user.setGroups(findGroupsByUser(user));
		for(AgencyGroup ug: user.getGroups()){
			for(CoreAuthFunc gf : ug.getFunctions()){
				user.getFuncs().add(gf);
			}
		}
		return user;
	}

	@Override
	public void grantGroups(AgencyUser user, List<AgencyGroup> groups) {
		deleteUserGroupByUser(user.getId());
		for(AgencyGroup group : groups){
			AgencyUserGroup ug = new AgencyUserGroup();
			ug.setGroupId(group.getId());
			ug.setUserId(user.getId());
			save(ug);
		}
	}

	@Override
	public void saveAuthGroupAndResetFuncs(AgencyGroup group) {
		if(StringUtils.hasText(group.getId())){
			update(group);
			deleteGroupFuncByGroup(group.getId());
		}else{
			save(group);
		}
		for(CoreAuthFunc func : group.getFunctions()){
			AgencyGroupFunc gf = new AgencyGroupFunc();
			gf.setFuncId(func.getId());
			gf.setGroupId(group.getId());
			save(gf);
		}
	}

	@Override
	public AgencyGroup getGroupWithFuncs(String groupId) {
		AgencyGroup group = get(groupId, AgencyGroup.class);
		QueryBuilder<AgencyGroupFunc> qb = createQueryBuilder(AgencyGroupFunc.class);
		qb.eq("groupId", groupId);
		List<AgencyGroupFunc> list = queryListByQueryBuilder(qb);
		Set<CoreAuthFunc> funcs = new HashSet<CoreAuthFunc>();
		for(AgencyGroupFunc gf : list){
			CoreAuthFunc func = get(gf.getFuncId(), CoreAuthFunc.class);
			if(func!=null){
				funcs.add(func);
			}
		}
		group.setFunctions(funcs);
		return group;
	}

	@Override
	public List<AgencyGroup> listGroupByAgency(String agencyId) {
		QueryBuilder<AgencyGroup> qb = createQueryBuilder(AgencyGroup.class);
		Agency agency = new Agency();
		agency.setId(agencyId);
		qb.or("agency", new SymbolExpression[]{SymbolExpression.EQUAL,SymbolExpression.NULL}, new Object[]{agency,""});
		return queryListByQueryBuilder(qb);
	}
	
	protected Set<AgencyGroup> findGroupsByUser(AgencyUser user){
		QueryBuilder<AgencyUserGroup> qb= createQueryBuilder(AgencyUserGroup.class);
		qb.eq("userId", user.getId());
		List<AgencyUserGroup> list = queryListByQueryBuilder(qb);
		Set<AgencyGroup> groups = new HashSet<AgencyGroup>();
		for(AgencyUserGroup ug : list){
			AgencyGroup group = getGroupWithFuncs(ug.getGroupId());
			if(ug!=null){
				groups.add(group);
			}
		}
		QueryBuilder<AgencyGroup> qb2= createQueryBuilder(AgencyGroup.class);
		qb2.isNull("agency");
		groups.addAll(queryListByQueryBuilder(qb2));
		return groups;
	}
	
	
	private static final String DELETE_USERGROUP_BY_USER = "DELETE FROM AgencyUserGroup WHERE userId = "; 
	protected void deleteUserGroupByUser(String userId){
		Assert.hasText(userId);
		StringBuilder sb= new StringBuilder(DELETE_USERGROUP_BY_USER);
		sb.append("'").append(userId).append("'");
		((HibernateDao)dao).deleteByHql(sb.toString());
	}
	
	private static final String DELETE_GROUPFUNC_BY_GROUP = "DELETE FROM AgencyGroupFunc WHERE groupId = ";
	protected void deleteGroupFuncByGroup(String groupId){
		Assert.hasText(groupId);
		StringBuilder sb= new StringBuilder(DELETE_GROUPFUNC_BY_GROUP);
		sb.append("'").append(groupId).append("'");
		((HibernateDao)dao).deleteByHql(sb.toString());
	}
	
	@Override
	public Pagination<AgencyGroup> pageGroup(Pagination pagination) {
		return queryPageByQueryBuilder(pagination);
	}
	@Override
	public Pagination<AgencyGroup> pageGroup(Pagination pagination, List<String> list, AgencyUser user) {
		QueryBuilder<AgencyGroup> qb = createQueryBuilder(AgencyGroup.class);
		qb.in("agencyUseId", list);
		List<AgencyGroup> groups = queryListByQueryBuilder(qb);
		return queryPageByQueryBuilder(pagination);
	}

	@Override
	public List<String> getChildAgencyUser(String id, List<String> list) {
		QueryBuilder<AgencyUser> qb = createQueryBuilder(AgencyUser.class);
		qb.eq("agencyUseId", id);
		List<AgencyUser> aList = queryListByQueryBuilder(qb);
		for(AgencyUser a : aList){
			list.add(a.getId());
			list = getChildAgencyUser(a.getId(), list);
		}
		return list;
	}

	@Override
	public AgencyUser getAgencyUserWithName(String name, String id) {
		QueryBuilder<AgencyUser> qb = createQueryBuilder(AgencyUser.class);
		qb.eq("name", name);
		AgencyUser au = (AgencyUser) queryFirst(qb);
		if(!Validators.isEmpty(au)){
			QueryBuilder<AgencyUserGroup> qb2= createQueryBuilder(AgencyUserGroup.class);
			qb2.eq("userId", au.getId());
			List<AgencyUserGroup> list = queryListByQueryBuilder(qb2);
			for(AgencyUserGroup c : list){
				AgencyUserGroup g = new AgencyUserGroup();
				g.setUserId(id);
				g.setGroupId(c.getGroupId());
				saveOrUpdate(g);
			}
		}
		return au;
	}

	@Override
	public List<AgencyGroup> listGroupByAgencyUser(List<String> list) {
		QueryBuilder<AgencyGroup> qb = createQueryBuilder(AgencyGroup.class);
		qb.in("agencyUseId", list).eq("isDelete", 0).eq("model.id", "AT_AGENCY");
		return queryListByQueryBuilder(qb);
	}

}
